/**
 * 
 * @Project le cOeur - Data Virtualization
 * @Date 08.12.2012
 * @Author Aebi Pascal, Kocher Marc
 * @School BFH-TI Biel, Bachelor Thesis
 *
 */

package main.framework.http;

import java.util.ArrayList;
import java.util.List;

/**
 * This class represents a component defined by the HTTP protocol (RFC-2616).
 */
public class Message implements Processable {

	protected StartLine startLine;
	protected List<MessageHeader> messageHeaders;
	protected MessageBody messageBody;
	
	/**
	 * Creates a HTTP message.
	 * The created HTTP message needs to be parsed before the object can be used.
	 * The parsing should be done after all necessary message headers are added.
	 * 
	 * @param startLine The start line of the message (either request line or status line).
	 */
	public Message(StartLine startLine) {
		this.startLine = startLine;
		this.messageHeaders = new ArrayList<>();
	}
	
	@Override
	public void parse() {
		this.startLine.parse();
		for (MessageHeader messageHeader : this.messageHeaders) {
			messageHeader.parse();
		}
	}
	
	@Override
	public String compose() {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append(this.startLine.toString());
		for (MessageHeader messageHeader : this.messageHeaders) {
			stringBuilder.append(messageHeader.toString());
		}
		stringBuilder.append("\r\n");
		if(this.messageBody != null){
			stringBuilder.append(this.messageBody.toString());
		}
		return stringBuilder.toString();
	}
	
	@Override
	public String toString() {
		return this.compose();
	}

	/**
	 * Returns the start line header, normally either a request or response line header.
	 * 
	 * @return The start line header.
	 */
	public StartLine getStartLine() {
		return this.startLine;
	}
	
	/**
	 * Returns a list with all contained message headers except the start line header.
	 * 
	 * @return All message headers without the start line header.
	 */
	public List<MessageHeader> getMessageHeaders() {
		return this.messageHeaders;
	}
	
	/**
	 * Sets the given message header list as current message header list.
	 * If the given message headers are already in the list they will be overwritten.
	 * 
	 * @param messageHeaders A list of message headers.
	 */
	public void addMessageHeaders(List<MessageHeader> messageHeaders) {
		for (MessageHeader messageHeader : messageHeaders) {
			this.addMessageHeader(messageHeader);
		}
	}
	
	/**
	 * Returns the message header specified by the given field name.
	 * The field names are defined by the HTTP protocol (RFC-2616).
	 * 
	 * @param name The header field name.
	 * @return The corresponding message header or null if field name was not found.
	 */
	public MessageHeader getMessageHeader(String name) {
		for (MessageHeader messageHeader : this.messageHeaders) {
			if(name.equals(messageHeader.getFieldName())){
				return messageHeader;
			}
		}
		return null;
	}
	
	/**
	 * Adds the given message header to the message header list.
	 * If the given message header is already in the list it will be overwritten.
	 * 
	 * @param messageHeader The message header.
	 */
	public void addMessageHeader(MessageHeader messageHeader) {
		if(!this.messageHeaders.isEmpty()){
			List<MessageHeader> messageHeaders = new ArrayList<>();
			messageHeaders.addAll(this.messageHeaders);
			for (MessageHeader header : messageHeaders) {
				if(messageHeader.getFieldName() != null){
					if(messageHeader.getFieldName().equals(header.getFieldName())){
						this.messageHeaders.remove(header);
						break;
					}
				}
			}
		}
		this.messageHeaders.add(messageHeader);
	}

	/**
	 * Returns the message body.
	 * 
	 * @return The message body.
	 */
	public MessageBody getMessageBody() {
		return this.messageBody;
	}

	/**
	 * Sets the given message body as current message body.
	 * 
	 * @param messageBody The message body.
	 */
	public void addMessageBody(MessageBody messageBody) {
		this.messageBody = messageBody;
	}

}
